/**
 * lineItem的mixins:用来存储所有与拖动有关的代码
 * */
import { dragItemSort } from '@veditor/components/timeLine/js/common';
import eventBus from '@veditor/eventBus';
import { isRangeOverlap } from '@veditor/components/timeLine/js/tools';

export default {
  props: {
    timelineItem: {
      required: true,
      type: Object,
    },
  },
  mounted() {
    document.addEventListener('mouseup', this.mouseup);
    document.addEventListener('mousedown', this.mouseup);
    document.addEventListener('mousemove', this.mousemove);
  },
  data() {
    return {
      dragItemList: [],
      currentIndex: -1,
      moving: false,
      classList: {
        'com-left drag-btn': 'left',
        'com-right drag-btn': 'right',
        'com-middle': 'middle',
        'content-text': 'middle',
        'content-img': 'middle',
        'block-item': 'middle',
        'audio-driver': 'middle',
        'text-driver': 'middle',
      },
      client: {
        clientX: 0,
        clientY: 0,
      },
      beforeLineStyle: {
        width: 0,
        left: 0,
        visible: false,
      },
      allWidth: 0, // 场景所占的宽度
      viewWidth: 0, // 全部可见的宽度
      dragRange: { timeRange: {}, rowRange: {} }, // 拖拽范围,
      moveDir: false,
      boundaryTimer: 0, // 开启一个定时器用于循环检测是否到达边界
      beforeScrollLeft: 0,
    };
  },
  methods: {
    mouseup() {
      const { dragItemList, currentIndex, moving, boundaryTimer } = this;
      if (moving) {
        this.moving = false;
        this.beforeLineStyle.visible = false;
        const currentEl = dragItemList[currentIndex];
        // 当前轴可以拖动,只需要有一个没有禁止就可以进入
        const canDrag = !this.disDragPos && !currentEl.row;
        const canTime = !this.disDragTime && !currentEl.time;
        if (canDrag || canTime) {
          this.judgeCollision(); // 处理拖拽结束的数据变化
        }
        Object.assign(currentEl, { current: '', click: false });
        this.currentIndex = -1;
      }
      boundaryTimer && cancelAnimationFrame(this.boundaryTimer);
    },
    mousedown(e, index) {
      if (this.timelineItem?.playing) {
        return;
      }
      eventBus.$emit('lineItemMouseDown');
      this.mouseup();
      const { dragItemList, beforeLineStyle, classList, dragRange } = this;
      const { lineStyle } = dragItemList[index];
      this.currentIndex = index;
      const current = classList[e.target.parentNode.className] || classList[e.target.className];
      this.client = { clientX: e.clientX, clientY: e.clientY };
      Object.assign(dragItemList[index], { click: true, current });
      Object.assign(beforeLineStyle, { width: lineStyle.width, left: lineStyle.left });
      Object.assign(dragRange, this.calcRange(index)); // 计算一下当前位置的最大值和最小值
      this.moving = true;
      this.click(index);
      this.judgeBoundary();
      this.beforeScrollLeft = this.getScrollLeft();
      this.mouseleave();
    },
    mousemove(e) {
      if (!this.moving) {
        return;
      }
      const { dragItemList, currentIndex, client, beforeScrollLeft } = this;
      const { current, lineStyle, row, time } = dragItemList[currentIndex];
      // 这里用来判断移动方向
      const { clientX, clientY } = client;
      const scrollLeftDiff = this.getScrollLeft() - beforeScrollLeft;
      const moveX = e.clientX - clientX + scrollLeftDiff;
      const moveY = e.clientY - clientY;
      this.moveDir = Math.abs(moveX) > Math.abs(moveY); // 为true则是x轴,为false 则是y轴
      if (this.moveDir) {
        this.calcPosition(current, moveX, lineStyle, row, time);
      }
    },
    // 用来计算左右的位置
    // eslint-disable-next-line sonarjs/cognitive-complexity,complexity
    calcPosition(current, moveX, lineStyle, row, time) {
      const minWidth = 12;
      const { allWidth, disDragPos, disDragTime, beforeLineStyle, dragRange } = this;
      const { width: bw, left: bl } = beforeLineStyle;
      const [minTime, maxTime] = dragRange.timeRange;
      const [minRow, maxRow] = dragRange.rowRange;
      const left = bl + moveX;
      const width = bw + moveX;
      // 这里需要得到父元素的开始时间
      if (current === 'left') {
        // 这里用于更新left的值和width,保持right的距离不改变
        const dragTimeFlag = !disDragTime && !time;
        if (dragTimeFlag) {
          if (left >= minTime && left + minWidth < bw + bl) {
            lineStyle.width = bw - moveX;
            lineStyle.left = left;
            this.timelineItem.calcBlockArr(lineStyle.width, allWidth);
          }
        }
      } else if (current === 'right') {
        // 这里用来计算right和width,保持left不改变
        const dragTimeFlag = !disDragTime && !time;
        if (dragTimeFlag) {
          if (width + bl > maxTime) {
            lineStyle.width = maxTime - bl;
          } else if (width < minWidth) {
            lineStyle.width = minWidth;
          } else {
            lineStyle.width = width;
          }
          this.timelineItem.calcBlockArr(lineStyle.width, allWidth);
        }
      } else if (current === 'middle') {
        beforeLineStyle.visible = true;
        const dragRowFlag = !disDragPos && !row;
        if (dragRowFlag) {
          if (left + bw > maxRow) {
            lineStyle.left = maxRow - bw;
          } else if (left < minRow) {
            lineStyle.left = minRow;
          } else {
            lineStyle.left = left;
          }
        }
        if (this.isFatherEl) {
          this.$emit('updateStyle', lineStyle);
        }
      }
    },
    // 计算点击元素的拖动范围
    calcRange(index) {
      const { dragItemList, allWidth, viewWidth, timelineItem, disExceedFlag } = this;
      const { fatherStartTime = 0 } = timelineItem;
      const fatherLeft = timelineItem.transformTimeToPx(fatherStartTime, allWidth);
      let min;
      let max;
      const beforeEl = dragItemList[index - 1];
      const afterEl = dragItemList[index + 1];
      if (beforeEl) {
        const { left, width } = beforeEl.lineStyle;
        min = left + width;
      } else {
        min = disExceedFlag ? 0 : -fatherLeft;
      }
      if (afterEl) {
        const { left } = afterEl.lineStyle;
        max = left;
      } else {
        max = disExceedFlag ? allWidth : viewWidth;
      }
      const exceedRowMax = this.getExceedMax();
      const rowMin = disExceedFlag ? 0 : -fatherLeft;
      const rowMax = disExceedFlag ? exceedRowMax : viewWidth;
      return { timeRange: [min, max], rowRange: [rowMin, rowMax] };
    },
    // 拖拽开始判断方向
    handleDragStart(e) {
      // 横轴移动或者上下禁用拖拽
      if (this.moveDir || this.disDrag) {
        e.stopPropagation();
        e.preventDefault();
      }
    },
    // 鼠标松手是否有冲突元素
    judgeCollision() {
      const { dragItemList, currentIndex, beforeLineStyle, allWidth, timelineItem, isFatherEl } =
        this;
      const { lineStyle } = dragItemList[currentIndex];
      const { left: bl, width: bw } = beforeLineStyle;
      const { left: nl, width: nw } = lineStyle;
      // 这里判断一下现在和之前数据是否一致
      if (!isFatherEl && bl === nl && bw === nw) {
        return;
      }
      this.handleMultiOrder();
      timelineItem.updateDataByArr(dragItemList, allWidth);
      timelineItem.resize(); // 只单独对line进行更新
    },
    // 用于处理单轴多元素拖拽结束时的顺序算法
    // eslint-disable-next-line sonarjs/cognitive-complexity,complexity
    handleMultiOrder() {
      const { dragItemList, currentIndex, beforeLineStyle, allWidth, timelineItem } = this;
      const copyDragItemList = JSON.parse(JSON.stringify(dragItemList));
      const { uid: beforeUid, lineStyle } = dragItemList[currentIndex];
      const { left: bl } = beforeLineStyle;
      const { left: nl } = lineStyle;
      const dir = bl - nl > 0; // 左边为true ,右边为false
      if (dragItemList.length > 1) {
        if (dir) {
          dragItemSort(dragItemList, 1, currentIndex); // 首先根据left排序
          timelineItem.currentSelect = dragItemList.findIndex(item => item.uid === beforeUid);
          for (let i = 0; i <= dragItemList.length; i++) {
            for (let j = i + 1; j < dragItemList.length; j++) {
              const item = dragItemList[i];
              const next = dragItemList[j];
              if (next) {
                const { width: iw, left: il } = item.lineStyle;
                const { width: nw, left: nl } = next.lineStyle;
                const beforeRange = [il, il + iw];
                const afterRange = [nl, nl + nw];
                if (isRangeOverlap(beforeRange, afterRange)) {
                  next.lineStyle.left = iw + il;
                } else {
                  break;
                }
              } else {
                break;
              }
            }
          }
        } else {
          dragItemSort(dragItemList, 1, currentIndex); // 首先根据left排序
          timelineItem.currentSelect = dragItemList.findIndex(item => item.uid === beforeUid);
          // @warning:这里可以优化少几次循环,没什么用,就不优化了,有break兜底
          for (let i = 0; i <= dragItemList.length; i++) {
            for (let j = i + 1; j < dragItemList.length; j++) {
              const item = dragItemList[i];
              const next = dragItemList[j];
              if (next) {
                const { width: iw, left: il } = item.lineStyle;
                const { width: nw, left: nl } = next.lineStyle;
                const beforeRange = [il, il + iw];
                const afterRange = [nl, nl + nw];
                if (isRangeOverlap(beforeRange, afterRange)) {
                  next.lineStyle.left = iw + il;
                } else {
                  break;
                }
                // 用于左拖动时的临界值判断.如果由于本次拖动有元素超出,则直接退回本次拖动
                const { left, width } = next.lineStyle;
                if (left + width > allWidth) {
                  dragItemList.splice(0, dragItemList.length);
                  dragItemList.push(...copyDragItemList);
                  Object.assign(dragItemList[currentIndex].lineStyle, beforeLineStyle);
                  timelineItem.currentSelect = currentIndex;
                  return;
                }
              } else {
                break;
              }
            }
          }
        }
      }
    },
    // 用于移动的时候判断边界
    // eslint-disable-next-line sonarjs/cognitive-complexity,complexity
    judgeBoundary() {
      if (this.currentIndex >= 0) {
        // 获取当前时间轴的scrollLeft
        const BORDER_WIDTH = 4;
        const SCROLL_DISTANCE = 10;
        const MAX_EXCEED_WIDTH = 20;
        const fatherEl = document.querySelector('.render-time-line-com');
        const containerEl = fatherEl.querySelector('.com-time');
        const scrollEl = fatherEl.querySelector('.com-drag');
        const { allWidth, dragItemList, currentIndex } = this;
        const { scrollLeft } = scrollEl;
        const { offsetWidth: visualWidth } = containerEl;
        const { lineStyle } = dragItemList[currentIndex];
        const { left, width } = lineStyle;
        let dir = 0;
        if (left + width + BORDER_WIDTH - scrollLeft >= visualWidth) {
          // 判断是否到了scrollLeft的边界
          if (left + width >= allWidth) {
            return;
          }
          dir = 1;
        } else if (left - scrollLeft <= 1) {
          if (left <= 0) {
            return;
          }
          dir = 2;
        }
        // 这里需要判断当前选中的元素有一个边超出了边框 并且 有一边超出边界
        const isExceed =
          left + MAX_EXCEED_WIDTH < scrollLeft ||
          left + width > scrollLeft + visualWidth + MAX_EXCEED_WIDTH;
        if (dir > 0 && !isExceed) {
          const diffValue = dir === 1 ? SCROLL_DISTANCE : -SCROLL_DISTANCE;
          let newScrollLeft = scrollLeft + diffValue;
          if (dir === 1) {
            const value = newScrollLeft + visualWidth - width - BORDER_WIDTH;
            if (value + width > allWidth) {
              lineStyle.left = allWidth - width;
            } else {
              lineStyle.left = value;
            }
          } else {
            if (newScrollLeft < 0) {
              newScrollLeft = 0;
            }
            lineStyle.left = newScrollLeft;
          }
          this.timelineItem.changeScroll({ target: { scrollLeft: newScrollLeft } });
        }
      }
      this.boundaryTimer = requestAnimationFrame(this.judgeBoundary);
    },
    // 获取当前的scrollLeft
    getScrollLeft() {
      const fatherEl = document.querySelector('.render-time-line-com');
      const scrollEl = fatherEl.querySelector('.com-drag');
      return scrollEl.scrollLeft;
    },
    // 用于获取lineItem的样式
    getLineItemStyle(item) {
      if (this.isFatherEl) {
        return { width: `${item.lineStyle.width}px`, left: 0 };
      } else {
        return { width: `${item.lineStyle.width}px`, left: `${item.lineStyle.left}px` };
      }
    },
    // 获取边界
    getExceedMax() {
      const { allWidth, viewWidth, timelineItem, disExceedFlag } = this;
      if (disExceedFlag) {
        const { fatherEl } = timelineItem;
        if (fatherEl) {
          const { duration: fatherElDuration } = fatherEl;
          return timelineItem.transformTimeToPx(fatherElDuration, allWidth);
        } else {
          return allWidth;
        }
      } else {
        return viewWidth;
      }
    },
  },
  beforeDestroy() {
    document.removeEventListener('mouseup', this.mouseup);
    document.removeEventListener('mousedown', this.mouseup);
    document.removeEventListener('mousemove', this.mousemove);
  },
};
